home *** CD-ROM | disk | FTP | other *** search
- // -----------------------------------------------------------------------------------------
- // general string/table functions
- // author: Martin D. Flynn
- // -------------------------------------------------------------------------------------
- // Permission is granted to freely redistribute this source code, and to use fragments
- // of this code in your own applications if you find them to be useful. This class,
- // along with the source code, come with no warranty of any kind, and the user assumes
- // all responsibility for its use.
- // -----------------------------------------------------------------------------------------
- extern "Objective-C" {
- #import <stdio.h>
- #import <string.h>
- #import <ctype.h>
- #import <libc.h>
- #import <pwd.h>
- #import <sys/types.h>
- #import <sys/stat.h>
- #import <sys/param.h>
- #import <sys/dir.h>
- }
-
- #import "ParseString.h"
-
- // -----------------------------------------------------------------------------------------
- // misc constants
- static int instId = 0;
- static char *lvalNull = (char*)NULL;
-
- // -----------------------------------------------------------------------------------------
- // new strings
-
- /* allocate new copy of string */
- inline char *new_String(const char *s)
- {
- return s? strcpy(new char[strlen(s) + 1], s) : (char*)NULL;
- }
-
- /* return directory table */
- #define BLOCK_SIZE 1024
- static char *new_ReadDirectoryList(const char *path)
- {
- int d, ls, listSize;
- DIR *dirp;
- char *dirs, *list;
- struct direct *dp;
-
- /* open directory */
- if (!path || !*path) return (char*)NULL;
- if (!(dirp = opendir(path))) return (char*)NULL;
-
- /* skip '.' & '..' */
- readdir(dirp); // skip "."
- readdir(dirp); // skip ".."
-
- /* read directory entries */
- dirs = (char*)malloc(ls = listSize = BLOCK_SIZE);
- for (*dirs = 0, d = 0; dp = readdir(dirp); d += dp->d_namlen) {
- while (d + dp->d_namlen + 2 > ls) ls += BLOCK_SIZE;
- if (ls > listSize) dirs = (char*)realloc(dirs, (listSize = ls));
- if (d) dirs[d++] = ' ';
- *(strncpy(&dirs[d], dp->d_name, dp->d_namlen) + dp->d_namlen) = 0;
- }
- closedir(dirp);
-
- /* allocate/return list */
- list = new_String(dirs);
- free(dirs);
- return list;
-
- }
- #undef BLOCK_SIZE
-
- /* read/return file contents */
- static char *new_ReadFileList(const char *fileName)
- {
- char *newlist = (char*)NULL;
- FILE *fhnd;
- struct stat st;
-
- /* stat file */
- if (stat(fileName, &st) != 0) return (char*)NULL;
-
- /* check for file directory */
- if (st.st_mode & S_IFDIR) return new_ReadDirectoryList(fileName);
-
- /* open/read file contents */
- fhnd = fopen(fileName, "r");
- if (fhnd) {
- int fLen = st.st_size;
- char list[fLen + 1];
- memset(list, 0, fLen + 1);
- if (fread(list, 1, fLen, fhnd) == fLen) {
- char *x, *z;
- for (x = z = list; x < list + fLen;) {
- for (; (x < list + fLen) && (*x <= ' '); x++);
- if (x >= list + fLen) break;
- if (z != list) *z++ = ' ';
- for (;(x < list + fLen) && (*x > ' '); z++, x++) if (z != x) *z = *x;
- }
- *z = 0;
- newlist = new_String(list);
- }
- fclose(fhnd);
- }
-
- return newlist;
- }
-
- // -----------------------------------------------------------------------------------------
- // constructors/destructor
-
- /* empty contructor */
- ParseString::ParseString()
- {
- instanceId = instId++;
- parseList = (char*)NULL;
- parseTable = (char**)NULL;
- }
-
- /* copy constructor */
- ParseString::ParseString(const ParseString &other)
- {
- instanceId = instId++;
- parseList = other.newUnparsedList();
- parseTable = this->_parseList(parseList);
- }
-
- /* list string contructor */
- ParseString::ParseString(const char *list)
- {
- instanceId = instId++;
- parseList = list? new_String(list) : (char*)NULL;
- parseTable = this->_parseList(parseList);
- }
-
- /* appended list constructor */
- ParseString::ParseString(const char *list1, const char *list2)
- {
- instanceId = instId++;
- parseList = this->_concatLists(list1, list2);
- parseTable = this->_parseList(parseList);
- }
-
- /* destructor */
- virtual ParseString::~ParseString()
- {
- instanceId = -instanceId;
- this->_clean();
- }
-
- // -----------------------------------------------------------------------------------------
- // operator overloading
-
- /* pipe from file name assignment "<<=" operator */
- /* Note: unfortunately 'ParseString ps <<= "filename"' isn't allowed. */
- ParseString & ParseString::operator<<=(const char *fileName)
- {
- this->_clean();
- parseList = new_ReadFileList(fileName);
- parseTable = this->_parseList(parseList);
- return *this;
- }
-
- /* assignment "=" operator */
- ParseString & ParseString::operator=(const ParseString &other)
- {
- if (&other == this) return *this; // self assignment
- this->_clean();
- parseList = other.newUnparsedList();
- parseTable = this->_parseList(parseList);
- return *this;
- }
-
- /* assignment "=" operator */
- ParseString & ParseString::operator=(const char *list)
- {
- this->_clean();
- parseList = new_String(list);
- parseTable = this->_parseList(parseList);
- return *this;
- }
-
- /* "+=" operator (append objects) */
- ParseString & ParseString::operator+=(const ParseString &second)
- {
- char *ptr1 = this->newUnparsedList();
- char *ptr2 = second.newUnparsedList();
- this->_clean();
- parseList = this->_concatLists(ptr1, ptr2);
- parseTable = this->_parseList(parseList);
- delete ptr1;
- delete ptr2;
- return *this;
- }
-
- /* "+=" operator (append objects) */
- ParseString & ParseString::operator+=(const char *list)
- {
- char *ptr1 = this->newUnparsedList();
- this->_clean();
- parseList = this->_concatLists(ptr1, list);
- parseTable = this->_parseList(parseList);
- delete ptr1;
- return *this;
- }
-
- /* "|=" operator (append objects) */
- ParseString & ParseString::operator|=(const ParseString &second)
- {
- ParseString ps(second);
- char **stbl = ps.table();
- if (!stbl) return ParseString(*this);
- char *ptr1 = this->newUnparsedList();
- for (int i = 0; stbl[i]; i++) if (this->indexTo(stbl[i]) >= 0) stbl[i] = "";
- char *ptr2 = ps.newUnparsedList();
- this->_clean();
- parseList = this->_concatLists(ptr1, ptr2);
- parseTable = this->_parseList(parseList);
- delete ptr1;
- delete ptr2;
- return *this;
- }
-
- /* "|=" operator (append objects) */
- ParseString & ParseString::operator|=(const char *list)
- {
- ParseString ps(list);
- char **stbl = ps.table();
- if (!stbl) return ParseString(*this);
- char *ptr1 = this->newUnparsedList();
- for (int i = 0; stbl[i]; i++) if (this->indexTo(stbl[i]) >= 0) stbl[i] = "";
- char *ptr2 = ps.newUnparsedList();
- this->_clean();
- parseList = this->_concatLists(ptr1, ptr2);
- parseTable = this->_parseList(parseList);
- delete ptr1;
- delete ptr2;
- return *this;
- }
-
- /* "+" operator (append objects) */
- ParseString ParseString::operator+(const ParseString &second) const
- {
- char *ptr1 = this->newUnparsedList();
- char *ptr2 = second.newUnparsedList();
- ParseString ps(ptr1, ptr2);
- delete ptr1;
- delete ptr2;
- return ps;
- }
-
- /* "+" operator (append objects) */
- ParseString ParseString::operator+(const char *list) const
- {
- char *ptr1 = this->newUnparsedList();
- ParseString ps(ptr1, list);
- delete ptr1;
- return ps;
- }
-
- /* "|" operator (merge objects) */
- ParseString ParseString::operator|(const ParseString &second) const
- {
- ParseString ps(second);
- char **stbl = ps.table();
-
- /* return copy of *this, if second contains no table */
- if (!stbl) return ParseString(*this);
-
- /* remove non-unique entries */
- char *ptr1 = this->newUnparsedList();
- for (int i = 0; stbl[i]; i++) if (this->indexTo(stbl[i]) >= 0) stbl[i] = "";
- char *ptr2 = ps.newUnparsedList();
- ParseString nps(ptr1, ptr2);
- delete ptr1;
- delete ptr2;
-
- return nps;
- }
-
- /* "|" operator (merge objects) */
- ParseString ParseString::operator|(const char *list) const
- {
- ParseString ps(list);
- char **stbl = ps.table();
-
- /* return copy of *this, if second contains no table */
- if (!stbl) return ParseString(*this);
-
- /* remove non-unique entries */
- char *ptr1 = this->newUnparsedList();
- for (int i = 0; stbl[i]; i++) if (this->indexTo(stbl[i]) >= 0) stbl[i] = "";
- char *ptr2 = ps.newUnparsedList();
- ParseString nps(ptr1, ptr2);
- delete ptr1;
- delete ptr2;
-
- return nps;
- }
-
- /* "[]" operator (reference items in table) */
- char * & ParseString::operator[](int ndx) const
- {
- char **tbl = this->table();
- if (!tbl) { lvalNull = (char*)NULL; return lvalNull; }
- return tbl[ndx];
- }
-
- /* "()" operator (return index to item in table) */
- int ParseString::operator()(const char *item) const
- {
- return this->indexTo(item);
- }
-
- // -----------------------------------------------------------------------------------------
- // member functions
-
- /* print table contents */
- void ParseString::print() const
- {
- int c;
- printf("Print ParseString table: (%d)\n", instanceId);
- if (!this->table()) return;
- for (c = 0; (*this)[c]; c++) printf(" %s\n", (*this)[c]);
- }
-
- /* return table array */
- char ** ParseString::table() const
- {
- return parseTable? parseTable : (char**)NULL;
- }
-
- /* return item count */
- int ParseString::count() const
- {
- int c;
- char **tbl = this->table();
- if (!tbl) return 0;
- for (c = 0; tbl[c]; c++);
- return c;
- }
-
- /* return table string length */
- int ParseString::unparsedLength() const
- {
- return this->_unparsedLength(this->table());
- }
-
- /* unparse table */
- char * ParseString::getUnparsedList(char *list, int listLen) const
- {
- return this->_unparseList(this->table(), list, listLen);
- }
-
- /* return new unparsed list */
- char * ParseString::newUnparsedList() const
- {
- return this->_newUnparsedList(this->table());
- }
-
- /* return index of specified item */
- int ParseString::indexTo(const char *entry) const
- {
- int i;
- char **tbl = this->table();
- if (!tbl) return -1;
- for (i = 0; tbl[i]; i++) if (!strcmp(tbl[i], entry)) return i;
- return -1;
- }
-
- /* return entry at index */
- char * ParseString::entryAt(int ndx) const
- {
- char **tbl = this->table();
- if (!tbl) return (char*)NULL;
- return tbl[ndx];
- }
-
- // -----------------------------------------------------------------------------------------
- // sorting
-
- /* sort compare routine */
- #define TOLOWER(C) (isupper(C)? tolower(C) : (C))
- virtual int ParseString::_sortCompare(char *p, char *q) const
- {
- register int i, j, d;
- for (; *p && *q; ) {
- if (isdigit(*p) && isdigit(*q)) {
- for (i = 0; isdigit(*p); i = i * 10 + *p++ - '0');
- for (j = 0; isdigit(*q); j = j * 10 + *q++ - '0');
- if (i != j) return i - j;
- continue;
- }
- if (d = TOLOWER(*p) - TOLOWER(*q)) return d;
- p++, q++;
- }
- return *p - *q;
- }
- #undef TOLOWER
-
- /* sort a string table (simple selection sort) */
- int ParseString::sort(int order = 0)
- {
- char **tbl = this->table();
- if (!tbl) return 0;
- for (int i = 0; tbl[i]; i++) {
- for (int j = i + 1; tbl[j]; j++) {
- int ri = !order? i : j;
- int rj = !order? j : i;
- if (this->_sortCompare(tbl[ri], tbl[rj]) > 0) {
- char *temp = tbl[ri];
- tbl[ri] = tbl[rj];
- tbl[rj] = temp;
- }
- }
- }
- return 1;
- }
-
- // -----------------------------------------------------------------------------------------
- // private functions
-
- /* clean house */
- void ParseString::_clean()
- {
- if (parseList) { delete parseList; parseList = (char*)NULL; }
- if (parseTable) { delete parseTable; parseTable = (char**)NULL; }
- }
-
- /* concat lists */
- char * ParseString::_concatLists(const char *list1, const char *list2)
- {
- const char *l1 = list1? list1 : "", *l2 = list2? list2 : "";
- char *newList = new char[(strlen(l1) + 1) + (strlen(l2) + 1)];
- sprintf(newList, "%s %s", l1, l2);
- return newList;
- }
-
- /* parse table */
- char ** ParseString::_parseList(char *list)
- {
- int c, n;
- char **tbl, *r;
-
- /* check string */
- if (!list) return (char**)NULL; // no string to parse
-
- /* skip whitespace in list */
- for (;isspace(*list);) list++;
- if (!*list) return (char**)NULL;
-
- /* count items in table */
- c = 0;
- r = list;
- while (isspace(*r)) r++;
- while (*r) {
- c++;
- while (*r && !isspace(*r)) r++; // skip value
- while (isspace(*r)) r++; // skip white
- }
- c++; // include NULL terminator
- tbl = new char*[c];
- memset(tbl, 0, c * sizeof(tbl[0]));
-
- /* fill table */
- for (n = 0, r = list; *r;) {
- tbl[n++] = r;
- while (*r && !isspace(*r)) r++;
- while (isspace(*r)) *r++ = 0;
- }
-
- /* return the table */
- return tbl;
-
- }
-
- /* return unparsed length of specified table */
- int ParseString::_unparsedLength(const char **tbl) const
- {
- int i, len;
- if (!tbl) return -1;
- for (i = 0, len = 0; tbl[i]; i++) len += strlen(tbl[i]) + 1;
- return len - 1;
- }
-
- /* unparse list */
- char * ParseString::_unparseList(char **tbl, char *list, int listLen) const
- {
- int i;
- char *lp;
- if (!tbl) return (char*)NULL;
- *list = 0;
- for (lp = list, i = 0; tbl[i]; i++) {
- if (lp + strlen(tbl[i]) + 1 - list > listLen) break; // overflow
- if ((lp > list) && (*(lp - 1) != ' ')) *lp++ = ' ';
- strcpy(lp, tbl[i]);
- lp += strlen(lp);
- }
- return list;
- }
-
- /* return new unparsed list */
- char * ParseString::_newUnparsedList(char **tbl) const
- {
- if (!tbl) return (char*)NULL;
- int listLen = this->_unparsedLength(tbl) + 1;
- char *list = new char[listLen];
- return this->_unparseList(tbl, list, listLen);
- }
-